<template>
    <div id='violin'>
        <div id="violin-chart" />
    </div>
</template>

<script>
    export default {
        name: "violin",
        props: {
            violinData: {
                type: Array,
                default: () => []
            },
        },
        watch: {
            violinData(val){
                if (val) {
                    d3.select('#violin-chart').selectAll('*').remove();
                    this.init()
                }
            },
        },
        components: {},
        data() {
            return {
                list: []
            }
        },
        created() {},
        mounted() {
            this.init()
        },
        methods: {
            init() {
                this.violinData.forEach(v => {
                    this.setViolin(v)
                })
            },
            setViolin(e) {
                // 设置图形的尺寸和边距
                const margin = {top: 10, right: 10, bottom: 30, left: 30}
                const num = Array.from(new Set(e.map(v => v.Species))).length * 160
                const width = num + 50
                const height = 300 - margin.top - margin.bottom
                // 将svg对象附加到页面主体
                const svg = d3.select("#violin-chart")
                    .append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append("g")
                    .attr("transform",
                        "translate(" + margin.left + "," + margin.top + ")");
                // 读取数据并计算每个规格的摘要统计信息
                const data = e
                data['columns'] = ['Sepal_Length', 'Species']
                const min = d3.min(data.map(v => v.Sepal_Length))
                const max = d3.max(data.map(v => v.Sepal_Length))
                const sumstat = d3.nest()
                    .key(function(d) { return d.Species;})
                    .rollup(function(d) {
                        let q1 = d3.quantile(d.map(function(g) { return g.Sepal_Length;}).sort(d3.ascending),.25)
                        let median = d3.quantile(d.map(function(g) { return g.Sepal_Length;}).sort(d3.ascending),.5)
                        let q3 = d3.quantile(d.map(function(g) { return g.Sepal_Length;}).sort(d3.ascending),.75)
                        let interQuantileRange = q3 - q1
                        let min = q1 - 1.5 * interQuantileRange
                        let max = q3 + 1.5 * interQuantileRange
                        return({q1: q1, median: median, q3: q3, interQuantileRange: interQuantileRange, min: min, max: max})
                    })
                    .entries(data)

                const x = d3.scaleBand()
                    .range([ 0, width ])
                    .domain(Array.from(new Set(data.map(v => v.Species))))
                    .paddingInner(1)
                    .paddingOuter(.5)
                svg.append("g")
                    .attr("transform", "translate(0," + height + ")")
                    .call(d3.axisBottom(x))

                const y = d3.scaleLinear()
                    .domain([+min - 1, +max + 1])
                    .range([height, 0])
                svg.append("g").attr('transform', 'translate(30, 0)').call(d3.axisLeft(y))
                    .append("text")
                    .text("Log2（RPM+1）")
                    .attr('x', -80)
                    .attr("transform","rotate(-90)")
                    .attr("fill","#000")
                    .attr("font-size", 13)
                    .attr("dy","-3.5em")

                svg
                    .selectAll("vertLines")
                    .data(sumstat)
                    .enter()
                    .append("line")
                    .attr("x1", function(d){return(x(d.key))})
                    .attr("x2", function(d){return(x(d.key))})
                    .attr("y1", function(d){return(y(d.value.min))})
                    .attr("y2", function(d){return(y(d.value.max))})
                    .attr("stroke", "black")
                    .style("width", 40)

                const boxWidth = 100
                svg
                    .selectAll("boxes")
                    .data(sumstat)
                    .enter()
                    .append("rect")
                    .attr("x", function(d){return(x(d.key)-boxWidth/2)})
                    .attr("y", function(d){return(y(d.value.q3))})
                    .attr("height", function(d){return(y(d.value.q1)-y(d.value.q3))})
                    .attr("width", boxWidth )
                    .attr("stroke", "black")
                    .style("fill", "#69b3a2")

                svg
                    .selectAll("medianLines")
                    .data(sumstat)
                    .enter()
                    .append("line")
                    .attr("x1", function(d){return(x(d.key)-boxWidth/2) })
                    .attr("x2", function(d){return(x(d.key)+boxWidth/2) })
                    .attr("y1", function(d){return(y(d.value.median))})
                    .attr("y2", function(d){return(y(d.value.median))})
                    .attr("stroke", "black")
                    .style("width", 80)

                const jitterWidth = 50
                svg
                    .selectAll("indPoints")
                    .data(data)
                    .enter()
                    .append("circle")
                    .attr("cx", function(d){return(x(d.Species) - jitterWidth/2 + Math.random()*jitterWidth )})
                    .attr("cy", function(d){return(y(d.Sepal_Length))})
                    .attr("r", 4)
                    .style("fill", "white")
                    .attr("stroke", "black")
            }
        }
    }
</script>

<style lang='stylus'>
.tick {
    text {
        transform: rotate(-4deg);
    }
}
#violin-chart {
    text-align: left;
    max-width: 1050px;
    margin: 0 auto;
    position relative
}
</style>
